#pragma once

//-----------------------------------------------------------------------------
// cMaterial
//-----------------------------------------------------------------------------
class cMaterial : public cClass {
public:
	struct Type {
		enum Enum {
			None, Parallax, Cartoon, Glass, Decal
		};
	};

	virtual const Type::Enum GetType() const {
		return Type::None;
	}

	cStr MaterialName;

	typedef cMaterial * cMaterialPtr;
	static int Compare(const cMaterialPtr *l, const cMaterialPtr *r) {
		return cStr::CompareNoCase((*l)->MaterialName, (*r)->MaterialName);
	}
	
	cClassCtor(cMaterial) {
	}
	
	cSaveClass(cMaterial)
		cRegEditS(MaterialName)
		cRegSeparator()
	cEndSave

	virtual void Create() {
		cAssert(0 && "Should be implemented");
	}
	
	const cStr ToString() {
		return MaterialName;
	}
	
	virtual int GetDiffuseMapID() const {
		return -1;
	}
	virtual int GetDiffuseWarpID() const {
		return -1;
	}
	virtual int GetNormalMapID() const {
		return -1;
	}
	virtual float GetHeightScale() const {
		return 0.0f;
	}
	virtual float GetHeightBias() const {
		return 0.0f;
	}
	virtual float GetRimBias() const {
		return 0.0f;
	}
	virtual float GetRimPower() const {
		return 0.0f;
	}
	virtual float GetSpecularPower() const {
		return 0.0f;
	}
	virtual float GetRefractionDepth() const {
		return 0.0f;
	}
	virtual float GetReflectionDepth() const {
		return 0.0f;
	}
	virtual const cColor GetColor() const {
		return cColor::Black;
	}
	virtual float GetAmbientCoeff() const {
		return 0.0f;
	}
	virtual float GetDiffuseCoeff() const {
		return 0.0f;
	}
	virtual bool GetAlphaTestEnabled() const {
		return false;
	}
	virtual float GetAlphaTestValue() const {
		return 0.0f;
	}
	virtual int GetDecalMapID() const {
		return -1;
	}
	virtual float GetMixRatio() const {
		return 0.0f;
	}
}; // cMaterial

//-----------------------------------------------------------------------------
// cMaterial_Parallax
//-----------------------------------------------------------------------------
class cMaterial_Parallax : public cMaterial {
public:
	const Type::Enum GetType() const {
		return Type::Parallax;
	}
	
	float ScaleZ;
	
	cSamplerState DiffuseMapSamplerState;
	cSamplerState NormalMapSamplerState;
	
	cImageSwatchFile DiffuseMap;
	cImageSwatchFile HeightMap;
	
	cVec3 HeightScale;
	cVec3 HeightBias;
	
	cClassCtor(cMaterial_Parallax) {
		m_DiffuseMapID = -1;
		m_NormalMapID = -1;
		m_Created = false;
		
		ScaleZ = 1.0f;
		DiffuseMapSamplerState.Filter = cFilter::Trilinear_Aniso;
		NormalMapSamplerState.Filter = cFilter::Trilinear_Aniso;
		
		HeightScale.Set(0.0f, 0.0f, 0.2f);
		HeightBias.Set(0.5f, 0.0f, 1.0f);
	}
	
	cClassDtor(cMaterial_Parallax) {
		Free();
	}
	
	cSaveClass(cMaterial_Parallax)
		cRegParent(cMaterial)
		
		cRegEditF(ScaleZ)
		cRegPanel(DiffuseMapSamplerState)
		cRegPanel(NormalMapSamplerState)
		cRegButton(&cMaterial_Parallax::ReCreate)
		cClassMode_Simple cRegPanel(DiffuseMap)
		cClassMode_Simple cRegPanel(HeightMap)
		cRegSliderRangedF(HeightScale)
		cRegSliderRangedF(HeightBias)
	cEndSave
	
	void Create();
	void Free();
	void ReCreate();
	
	int GetDiffuseMapID() const {
		return m_DiffuseMapID;
	}
	int GetNormalMapID() const {
		return m_NormalMapID;
	}
	float GetHeightScale() const {
		return HeightScale.x;
	}
	float GetHeightBias() const {
		return HeightBias.x;
	}
private:
	bool m_Created;
	
	int m_DiffuseMapID;
	int m_NormalMapID;
}; // cMaterial_Parallax

//-----------------------------------------------------------------------------
// cMaterial_ParallaxNormal
//-----------------------------------------------------------------------------
class cMaterial_ParallaxNormal : public cMaterial {
public:
	const Type::Enum GetType() const {
		return Type::Parallax;
	}
	
	cSamplerState DiffuseMapSamplerState;
	cSamplerState NormalMapSamplerState;

	cImageSwatchFile DiffuseMap;
	cImageSwatchFile NormalMap;

	cVec3 HeightScale;
	cVec3 HeightBias;

	cClassCtor(cMaterial_ParallaxNormal) {
		m_DiffuseMapID = -1;
		m_NormalMapID = -1;

		HeightScale.Set(0.0f, 0.0f, 0.2f);
		HeightBias.Set(0.5f, 0.0f, 1.0f);
		DiffuseMapSamplerState.Filter = cFilter::Trilinear_Aniso;
		NormalMapSamplerState.Filter = cFilter::Trilinear_Aniso;

		m_Created = false;
	}

	cClassDtor(cMaterial_ParallaxNormal) {
		Free();
	}

	cSaveClass(cMaterial_ParallaxNormal)
		cRegParent(cMaterial)

		cRegPanel(DiffuseMapSamplerState)
		cRegPanel(NormalMapSamplerState)
		cRegButton(&cMaterial_ParallaxNormal::ReCreate)
		cClassMode_Simple cRegPanel(DiffuseMap)
		cClassMode_Simple cRegPanel(NormalMap)
		cRegSliderRangedF(HeightScale)
		cRegSliderRangedF(HeightBias)
	cEndSave

	void Create();
	void Free();
	void ReCreate();

	int GetDiffuseMapID() const {
		return m_DiffuseMapID;
	}
	int GetNormalMapID() const {
		return m_NormalMapID;
	}
	float GetHeightScale() const {
		return HeightScale.x;
	}
	float GetHeightBias() const {
		return HeightBias.x;
	}
private:
	bool m_Created;
	
	int m_DiffuseMapID;
	int m_NormalMapID;
}; // cMaterial_ParallaxNormal

//-----------------------------------------------------------------------------
// cMaterial_Cartoon
//-----------------------------------------------------------------------------
class cMaterial_Cartoon : public cMaterial {
public:
	const Type::Enum GetType() const {
		return Type::Cartoon;
	}

	float ScaleZ;

	cSamplerState DiffuseMapSamplerState;
	cSamplerState DiffuseWarpSamplerState;
	cSamplerState NormalMapSamplerState;
	
	cImageSwatchFile DiffuseMap;
	cImageSwatchFile DiffuseWarp;
	cImageSwatchFile HeightMap;
	
	cVec3 RimBias;
	cVec3 RimPower;
	cVec3 SpecularPower;
	
	cClassCtor(cMaterial_Cartoon) {
		m_DiffuseMapID = -1;
		m_DiffuseWarpID = -1;
		m_NormalMapID = -1;
		
		ScaleZ = 1.0f;
		DiffuseMapSamplerState.Filter = cFilter::Trilinear_Aniso;
		DiffuseWarpSamplerState.Filter = cFilter::Linear;
		DiffuseWarpSamplerState.s = DiffuseWarpSamplerState.t = DiffuseWarpSamplerState.r = cAddressMode::Clamp;
		NormalMapSamplerState.Filter = cFilter::Trilinear_Aniso;
		
		RimBias.Set(0.2f, 0.0f, 1.0f);
		RimPower.Set(10.0f, 0.0f, 64.0f);
		SpecularPower.Set(30.0f, 0.0f, 64.0f);

		m_Created = false;
	}

	cClassDtor(cMaterial_Cartoon) {
		Free();
	}

	cSaveClass(cMaterial_Cartoon)
		cRegParent(cMaterial)

		cRegEditF(ScaleZ)
		cRegPanel(DiffuseMapSamplerState)
		cRegPanel(DiffuseWarpSamplerState)
		cRegPanel(NormalMapSamplerState)
		cRegButton(&cMaterial_Cartoon::ReCreate)
		cClassMode_Simple cRegPanel(DiffuseMap)
		cClassMode_Simple cRegPanel(DiffuseWarp)
		cClassMode_Simple cRegPanel(HeightMap)
		cRegSliderRangedF(RimBias)
		cRegSliderRangedF(RimPower)
		cRegSliderRangedF(SpecularPower)
	cEndSave

	void Create();
	void Free();
	void ReCreate();

	int GetDiffuseMapID() const {
		return m_DiffuseMapID;
	}
	int GetDiffuseWarpID() const {
		return m_DiffuseWarpID;
	}
	int GetNormalMapID() const {
		return m_NormalMapID;
	}
	float GetRimBias() const {
		return RimBias.x;
	}
	float GetRimPower() const {
		return RimPower.x;
	}
	float GetSpecularPower() const {
		return SpecularPower.x;
	}
private:
	bool m_Created;

	int m_DiffuseMapID;
	int m_DiffuseWarpID;
	int m_NormalMapID;
}; // cMaterial_Cartoon

//-----------------------------------------------------------------------------
// cMaterial_CartoonNormal
//-----------------------------------------------------------------------------'
class cMaterial_CartoonNormal : public cMaterial {
public:
	const Type::Enum GetType() const {
		return Type::Cartoon;
	}
	
	cSamplerState DiffuseMapSamplerState;
	cSamplerState DiffuseWarpSamplerState;
	cSamplerState NormalMapSamplerState;

	cImageSwatchFile DiffuseMap;
	cImageSwatchFile DiffuseWarp;
	cImageSwatchFile NormalMap;
	
	cVec3 RimBias;
	cVec3 RimPower;
	cVec3 SpecularPower;
	
	cClassCtor(cMaterial_CartoonNormal) {
		m_DiffuseMapID = -1;
		m_DiffuseWarpID = -1;
		m_NormalMapID = -1;
		
		DiffuseMapSamplerState.Filter = cFilter::Trilinear_Aniso;
		DiffuseWarpSamplerState.Filter = cFilter::Linear;
		DiffuseWarpSamplerState.s = DiffuseWarpSamplerState.t = DiffuseWarpSamplerState.r = cAddressMode::Clamp;
		NormalMapSamplerState.Filter = cFilter::Trilinear_Aniso;
		
		RimBias.Set(0.2f, 0.0f, 1.0f);
		RimPower.Set(10.0f, 0.0f, 64.0f);
		SpecularPower.Set(30.0f, 0.0f, 64.0f);

		m_Created = false;
	}

	cClassDtor(cMaterial_CartoonNormal) {
		Free();
	}

	cSaveClass(cMaterial_CartoonNormal)
		cRegParent(cMaterial)

		cRegPanel(DiffuseMapSamplerState)
		cRegPanel(DiffuseWarpSamplerState)
		cRegPanel(NormalMapSamplerState)
		cRegButton(&cMaterial_CartoonNormal::ReCreate)
		cClassMode_Simple cRegPanel(DiffuseMap)
		cClassMode_Simple cRegPanel(DiffuseWarp)
		cClassMode_Simple cRegPanel(NormalMap)
		cRegSliderRangedF(RimBias)
		cRegSliderRangedF(RimPower)
		cRegSliderRangedF(SpecularPower)
	cEndSave

	void Create();
	void Free();
	void ReCreate();

	int GetDiffuseMapID() const {
		return m_DiffuseMapID;
	}
	int GetDiffuseWarpID() const {
		return m_DiffuseWarpID;
	}
	int GetNormalMapID() const {
		return m_NormalMapID;
	}
	float GetRimBias() const {
		return RimBias.x;
	}
	float GetRimPower() const {
		return RimPower.x;
	}
	float GetSpecularPower() const {
		return SpecularPower.x;
	}
private:
	bool m_Created;

	int m_DiffuseMapID;
	int m_DiffuseWarpID;
	int m_NormalMapID;
}; // cMaterial_CartoonNormal

//-----------------------------------------------------------------------------
// cMaterial_Glass
//-----------------------------------------------------------------------------
class cMaterial_Glass : public cMaterial {
public:
	cVec3 RefractionDepth;
	cVec3 ReflectionDepth;
	cColorEdit Color;
	cVec3 AmbientCoeff;
	cVec3 DiffuseCoeff;
	cVec3 MixRatio;
	
	const Type::Enum GetType() const {
		return Type::Glass;
	}

	cClassCtor(cMaterial_Glass) {
		m_Created = false;
		
		// Defaults
		RefractionDepth.Set(0.1f, 0.0f, 1.0f);
		ReflectionDepth.Set(-1.5f, -2.0f, 0.0f);
		Color.Color.Set(0.4f, 0.4f, 1.0f, 1.0f);
		AmbientCoeff.Set(0.2f, 0.0f, 1.0f);
		DiffuseCoeff.Set(3.0f, 0.0f, 5.0f);
		MixRatio.Set(1.0f, 0.0f, 1.0f);
	}

	cClassDtor(cMaterial_Glass) {
		Free();
	}

	cSaveClass(cMaterial_Glass)
		cRegParent(cMaterial)

		cRegButton(&cMaterial_Glass::ReCreate)
		cClassMode_Simple cRegPanel(Color)
		cRegSliderRangedF(ReflectionDepth)
		cRegSliderRangedF(RefractionDepth)
		cRegSliderRangedF(AmbientCoeff)
		cRegSliderRangedF(DiffuseCoeff)
		cRegSliderRangedF(MixRatio)
	cEndSave

	void Create();
	void Free();
	void ReCreate();
	
	const cColor GetColor() const {
		return Color.Color;
	}
	float GetReflectionDepth() const {
		return ReflectionDepth.x;
	}
	float GetRefractionDepth() const {
		return RefractionDepth.x;
	}
	float GetAmbientCoeff() const {
		return AmbientCoeff.x;
	}
	float GetDiffuseCoeff() const {
		return DiffuseCoeff.x;
	}
	float GetMixRatio() const {
		return MixRatio.x;
	}
private:
	bool m_Created;
}; // cMaterial_Glass

//-----------------------------------------------------------------------------
// cMaterial_Decal
//-----------------------------------------------------------------------------
class cMaterial_Decal : public cMaterial {
public:
	const Type::Enum GetType() const {
		return Type::Decal;
	}

	cSamplerState DecalMapSamplerState;
	cImageSwatchFile DecalMap;
	cColorEdit Color0;
	cColorEdit Color1;
	float Modulator0;
	float Modulator1;
	float PeriodSec;
	
	cClassCtor(cMaterial_Decal) {
		m_DecalMapID = -1;
		m_Created = false;
		m_StartTimeSec = 0.0f;
		
		DecalMapSamplerState.Filter = cFilter::Trilinear_Aniso;
		Color0.Color = Color1.Color = cColor::White;
		Modulator0 = 1.0f;
		Modulator1 = 1.0f;
		PeriodSec = 1.0f;
	}
	
	cClassDtor(cMaterial_Decal) {
		Free();
	}
	
	cSaveClass(cMaterial_Decal)
		cRegParent(cMaterial)
		
		cRegPanel(DecalMapSamplerState)
		cRegButton(&cMaterial_Decal::ReCreate)
		cClassMode_Simple cRegPanel(DecalMap)
		cClassMode_Simple cRegPanel(Color0)
		cClassMode_Simple cRegPanel(Color1)
		cRegEditF(Modulator0)
		cRegEditF(Modulator1)
		cRegEditF(PeriodSec)
		cRegButton(&cMaterial_Decal::SwapColors)
	cEndSave
	
	void Create();
	void Free();
	void ReCreate();
	void SwapColors();
	
	int GetDecalMapID() const {
		return m_DecalMapID;
	}
	const cColor GetColor() const;
private:
	bool m_Created;
	
	int m_DecalMapID;
	float m_StartTimeSec;
}; // cMaterial_Decal

//-----------------------------------------------------------------------------
// cMaterialsGroup
//-----------------------------------------------------------------------------
class cMaterialsGroup : public cClass {
public:
	cStr GroupName;
	cClassList<cMaterial> Materials;

	cClassCtor(cMaterialsGroup) {
	}

	void Sort() {
		Materials.Sort(cMaterial::Compare);
	}

	cSaveClass(cMaterialsGroup)
		cRegEditS(GroupName)
		cRegButton(&cMaterialsGroup::Sort)
		cClassMode_Simple cRegPanel(Materials)
	cEndSave

	const cStr ToString() {
		return GroupName;
	}
}; // cMaterialsGroup

//-----------------------------------------------------------------------------
// cMaterials
//-----------------------------------------------------------------------------
class cMaterials : public cClass {
public:
	cClassList<cMaterialsGroup> Groups;
	
	cClassCtor(cMaterials) {
	}
	
	int GetMaterialID(const char *MaterialName);
	const cMaterial * GetMaterial(const int MaterialID) const;
	cMaterial * GetMaterialMutable(const int MaterialID);


	cSaveClass(cMaterials)
		cRegClass(cMaterial)
		cRegClass(cMaterial_Parallax)
		cRegClass(cMaterial_ParallaxNormal)
		cRegClass(cMaterial_Cartoon)
		cRegClass(cMaterial_CartoonNormal)
		cRegClass(cMaterial_Glass)
		cRegClass(cMaterial_Decal)
		cRegClass(cMaterialsGroup)
		
		cClassMode_Simple cRegPanel(Groups)
	cEndSave
}; // cMaterials

extern cMaterials g_Materials;